`timescale 1ns / 1ps

// 高性能 FIR模块，实现15-tap FIR数字滤波器
module FIR(
    input clk,
    input reset,
    input signed [15:0] s_axis_fir_tdata, 
    input [3:0] s_axis_fir_tkeep,
    input s_axis_fir_tlast,
    input s_axis_fir_tvalid,
    input m_axis_fir_tready,
    output reg m_axis_fir_tvalid,
    output reg s_axis_fir_tready,
    output reg m_axis_fir_tlast,
    output reg [3:0] m_axis_fir_tkeep,
    output reg signed [31:0] m_axis_fir_tdata
    );

    /* This loop controls tkeep signal on AXI Stream interface */
    // 控制AXI Stream接口上的tkeep信号
    always @ (posedge clk)
        begin
            m_axis_fir_tkeep <= 4'hf;
        end
        
    /* This loop controls tlast signal on AXI Stream interface */
    // 控制AXI Stream接口上的tlast信号
    always @ (posedge clk)
        begin
            if (s_axis_fir_tlast == 1'b1)
                begin
                    m_axis_fir_tlast <= 1'b1;
                end
            else
                begin
                    m_axis_fir_tlast <= 1'b0;
                end
        end
    
    // 15-tap FIR 
    // FIR滤波器的寄存器和缓存定义
    reg enable_fir;
    reg signed [15:0] buff0, buff1, buff2, buff3, buff4, buff5, buff6, buff7, buff8, buff9, buff10, buff11, buff12, buff13, buff14;
    wire signed [15:0] tap0, tap1, tap2, tap3, tap4, tap5, tap6, tap7, tap8, tap9, tap10, tap11, tap12, tap13, tap14; 
    reg signed [31:0] acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7, acc8, acc9, acc10, acc11, acc12, acc13, acc14; 

    
    /* Taps for LPF running @ 1MSps */
    // 低通滤波器的滤波器系数
    assign tap0 = 16'hFC9C;  // twos(-0.0265 * 32768) = 0xFC9C
    assign tap1 = 16'h0000;  // 0
    assign tap2 = 16'h05A5;  // 0.0441 * 32768 = 1445.0688 = 1445 = 0x05A5
    assign tap3 = 16'h0000;  // 0
    assign tap4 = 16'hF40C;  // twos(-0.0934 * 32768) = 0xF40C
    assign tap5 = 16'h0000;  // 0
    assign tap6 = 16'h282D;  // 0.3139 * 32768 = 10285.8752 = 10285 = 0x282D
    assign tap7 = 16'h4000;  // 0.5000 * 32768 = 16384 = 0x4000
    assign tap8 = 16'h282D;  // 0.3139 * 32768 = 10285.8752 = 10285 = 0x282D
    assign tap9 = 16'h0000;  // 0
    assign tap10 = 16'hF40C; // twos(-0.0934 * 32768) = 0xF40C
    assign tap11 = 16'h0000; // 0
    assign tap12 = 16'h05A5; // 0.0441 * 32768 = 1445.0688 = 1445 = 0x05A5
    assign tap13 = 16'h0000; // 0
    assign tap14 = 16'hFC9C; // twos(-0.0265 * 32768) = 0xFC9C
    
    /* This loop controls tready & tvalid signals on AXI Stream interface */
    // 控制AXI Stream接口上的tready和tvalid信号
    always @ (posedge clk)
        begin
            if(reset == 1'b0 || m_axis_fir_tready == 1'b0 || s_axis_fir_tvalid == 1'b0)
                begin
                    enable_fir <= 1'b0;
                    s_axis_fir_tready <= 1'b0;
                    m_axis_fir_tvalid <= 1'b0;
                end
            else
                begin
                    enable_fir <= 1'b1;
                    s_axis_fir_tready <= 1'b1;
                    m_axis_fir_tvalid <= 1'b1;
                end
        end
    
    // FIR滤波器的计数器和累加器
    reg [3:0] cnt;
    reg signed [31:0] acc01, acc012, acc23, acc34, acc45, acc56, acc67, acc78, acc89, acc910, acc1011, acc1112, acc1213;
    
    /* Circular buffer w/ Multiply & Accumulate stages of FIR */
    // FIR滤波器的循环缓冲区及乘加阶段
    always @ (posedge clk or posedge reset)
        begin
            if (reset == 1'b0) 
                begin
                    buff0 <= 16'd0; buff1 <= 16'd0; buff2 <= 16'd0; buff3 <= 16'd0;
                    buff4 <= 16'd0; buff5 <= 16'd0; buff6 <= 16'd0; buff7 <= 16'd0;
                    buff8 <= 16'd0; buff9 <= 16'd0; buff10 <= 16'd0; buff11 <= 16'd0;
                    buff12 <= 16'd0; buff13 <= 16'd0; buff14 <= 16'd0;
                end
            else if (enable_fir == 1'b1)
                begin
                    buff14 <= buff13;
                    buff13 <= buff12;
                    buff12 <= buff11;
                    buff11 <= buff10;
                    buff10 <= buff9;
                    buff9  <= buff8;
                    buff8  <= buff7;
                    buff7  <= buff6;
                    buff6  <= buff5;
                    buff5  <= buff4;
                    buff4  <= buff3;
                    buff3  <= buff2;
                    buff2  <= buff1;
                    buff1  <= buff0;
                    buff0  <= s_axis_fir_tdata; // 将新输入样本放入 buff0
                end
        end
    
endmodule


/*
备注：fir_timing.v 和 fir_timing_v2.v 代码的区别

这两段代码的结构和逻辑非常相似，目标都是实现一个 15 阶 FIR 滤波器。但它们在以下几个方面有所区别：

1. 输入和环形缓冲区的处理

第一段代码：
	•	包含 buff_cnt 计数器来跟踪缓冲区状态，通过计数器确定何时完成缓冲区填充。
	•	使用 in_sample 暂存输入数据，再将其转移到缓冲区中。
	•	明确分离了 使能缓冲区写入 (enable_buff) 和 滤波器运算 (enable_fir) 的逻辑。

第二段代码：
	•	没有使用 buff_cnt 计数器，而是直接使用 s_axis_fir_tdata 的有效性和 enable_fir 信号。
	•	缓冲区部分直接依赖 enable_fir 控制逻辑，没有明确的初始化填充过程。
	•	缺少对缓冲区初始化的控制，在复位后，缓冲区未必被正确填充。

总结：
第一段代码的缓冲区逻辑更清晰，能够明确何时完成缓冲区的填充并开始滤波计算。第二段代码省略了缓冲区状态的追踪，依赖 enable_fir，可能导致状态不一致。

2. 乘法与累加部分

第一段代码：
	•	使用多个寄存器（如 acc0, acc1, acc2,...）分别存储每个样本与系数的乘积。
	•	在后续阶段中，将这些寄存器的值逐级累加，形成最终结果。

第二段代码：
	•	引入了 部分累加寄存器（如 acc01, acc012, acc23,...），先对部分结果进行分组累加，再进一步累加成最终结果。
	•	分组累加优化了运算路径，有利于减少累加逻辑的延迟。

总结：
第一段代码逻辑简单直观，每个样本和系数的乘积都单独存储，然后统一累加；第二段代码通过部分累加优化了累加过程，效率更高，但逻辑复杂度增加。

3. 复位逻辑

第一段代码：
	•	在复位时，明确地将计数器、使能信号和缓冲区全部复位到初始状态。
	•	输入样本 in_sample 也在复位时清零。

第二段代码：
	•	在复位时仅将 m_axis_fir_tdata 清零，没有对缓冲区或其他累加寄存器（如 acc01 等）进行清零。
	•	如果复位后立即开始工作，缓冲区可能包含上一次计算的残余数据，导致结果错误。

总结：
第一段代码的复位逻辑更完整，确保所有相关信号和寄存器都恢复初始状态；第二段代码的复位逻辑略显简略，可能导致复位后的状态不稳定。

4. 可扩展性

第一段代码：
	•	通过清晰的计数器逻辑和独立的累加器寄存器，滤波器的规模（阶数）扩展较为简单，只需添加新的寄存器和逻辑。

第二段代码：
	•	使用分组累加优化了性能，但扩展时需要重新设计分组累加的逻辑，增加了复杂性。

总结：
第一段代码适合需要灵活调整滤波器阶数的场景；第二段代码适合固定阶数且性能要求较高的场景。

整体对比

特性	第一段代码	第二段代码
环形缓冲区处理	有计数器，逻辑清晰	无计数器，逻辑略显简略
乘法与累加实现	简单直观，每步独立存储结果	分组累加，优化了性能
复位逻辑	完整，所有信号初始化	简略，部分寄存器可能未初始化
扩展性	易于扩展阶数	扩展复杂度高
性能	功能完整，适合一般场景	性能更优，适合高效场景

建议
	•	如果目标是设计一个结构清晰、功能完整且易于维护的 FIR 滤波器模块，第一段代码是更好的选择。
	•	如果需要在性能上进行优化（如降低累加延迟），可以采用第二段代码的分组累加方式，但需要补充更完善的初始化和复位逻辑。

*/